﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace DARE
{
    public class CProcessList
    {
        public CProcessList()
        {
            added = new Dictionary<int, float>();
            items = new List<IPartitionerItem>();
            itemsNumber = 0;
        }

        public CProcessList(int capacity)
        {
            added = new Dictionary<int, float>();
            items = new List<IPartitionerItem>();
            items.Capacity = capacity;
            itemsNumber = 0;
        }

        public virtual bool AddItem(IPartitionerItem item)
        {
            if (added.ContainsKey(item.Id))
            {
                added[item.Id] += 1; 
                return false;
            }
            added.Add(item.Id, -1);
            items.Add(item);
            itemsNumber += 1;
            return true;
        }

        public virtual bool AddItemAt(int pos, IPartitionerItem item)
        {
            if (added.ContainsKey(item.Id))
            {
                added[item.Id] += 1; 
                return false;
            }
            added.Add(item.Id, -1);
            items.Insert(pos, item);
            itemsNumber += 1;
            return true;
        }

        public virtual void Clear()
        {
            added.Clear();
            items.Clear();
            itemsNumber = 0;
        }

        public Dictionary<int, float> added;
        public List<IPartitionerItem> items;
        public int itemsNumber;
    }

    public class CRegularList : CProcessList
    {
        public CRegularList() :
            base()
        { }

        public CRegularList(int capacity) : 
            base(capacity)
        { }

        public bool AddItem(Vector3 camPos, IPartitionerItem item)
        {
            float camDist = Vector3.DistanceSquared(camPos, item.Position);

            if (added.ContainsKey(item.Id))
            {
                added[item.Id] += 1;
                return false;
            }
            added.Add(item.Id, camDist);
            items.Add(item);
            itemsNumber += 1;
            item.DistFromCam = camDist;
            return true;
        }
    }

    public class CFrontToBackList : CProcessList
    {
        public CFrontToBackList() :
            base()
        { }

        public CFrontToBackList(int capacity) : 
            base(capacity)
        { }

        public bool AddItem(Vector3 camPos, IPartitionerItem item)
        {
            // do nothing if the item is already in the list
            if (added.ContainsKey(item.Id))
                return false;

            float camDist = Vector3.DistanceSquared(camPos, item.Position);

            int begin = 0;
            int middle = 0;
            int end = itemsNumber - 1;
            float dist = 0;

            while (begin <= end)
            {
                middle = (begin + end) / 2; // get the mid point
                dist = added[items.ElementAt(middle).Id];

                if (camDist > dist) // repeat search in top half
                    begin = middle + 1;
                else if (camDist < dist) // repeat search in bottom half
                    end = middle - 1;
                else
                    break;
            }

            // add the item
            added.Add(item.Id, camDist);
            items.Insert(begin, item);
            itemsNumber += 1;
            item.DistFromCam = camDist;
            return true;
        }
    }

    public class CBackToFrontList : CProcessList
    {
        public CBackToFrontList() :
            base()
        { }

        public CBackToFrontList(int capacity) : 
            base(capacity) 
        { }

        public bool AddItem(Vector3 camPos, IPartitionerItem item)
        {
            // do nothing if the item is already in the list
            if (added.ContainsKey(item.Id))
                return false;

            float camDist = Vector3.DistanceSquared(camPos, item.Position);

            int begin = 0;
            int middle = 0;
            int end = itemsNumber - 1;
            float dist = 0;

            while (begin <= end)
            {
                middle = (begin + end) / 2; // get the mid point
                dist = added[items.ElementAt(middle).Id];

                if (camDist < dist) // repeat search in top half
                    begin = middle + 1;
                else if (camDist > dist) // repeat search in bottom half
                    end = middle - 1;
                else
                    break;
            }

            // add the item
            added.Add(item.Id, camDist);
            items.Insert(begin, item);
            itemsNumber += 1;
            item.DistFromCam = camDist;
            return true;
        }
    }
}
